﻿using Bigway.Common.Models.DtoModels;
using Microsoft.Extensions.Configuration;
using Flurl;
using Flurl.Http;
using System.Text.Json;
using Flurl.Http.Configuration;

namespace Bigway.Common.Services;

public class BigwayApiClient(IConfiguration configuration): IBigwayApiClient
{
    private readonly string _apiKey = configuration.GetValue<string>("ApiKey")!;

    public async Task<TResponse> InvokeAsyncWithJsonResponse<TRequestBody, TResponse>(HttpMethod method,
        string baseUrl,
        Dictionary<string, object>? query = default,
        TRequestBody? body = default,
        CancellationToken token = default)
        where TRequestBody : class
        where TResponse : BaseResponseDto, new()
    {
        var requestUrl = baseUrl.AppendQueryParam("api_key", _apiKey);
        var request = requestUrl.WithSettings(settings =>
        {
            settings.JsonSerializer = new DefaultJsonSerializer(CommonStatics.DefaultJsonOptions);
        });
        foreach (var (key, value) in query?? [])
        {
            request = request.AppendQueryParam(key, value);
        }

        if (method == HttpMethod.Get)
        {
            return await request.
                GetJsonAsync<TResponse>(cancellationToken: token);
        }

        IFlurlResponse? response;

        if (method == HttpMethod.Post)
        {
            if (body is not null)
            {
                response = await request.PostJsonAsync(body, cancellationToken: token);
            }
            else
            {
                response = await request.PostAsync(cancellationToken: token);
            }
        }
        else if (method == HttpMethod.Put)
        {
            if (body is not null)
            {
                response = await request.PutJsonAsync(body, cancellationToken: token);
            }
            else
            {
                response = await request.PutAsync(cancellationToken: token);
            }
        }
        else if (method == HttpMethod.Delete)
        {
            response = await request.DeleteAsync(cancellationToken: token);
        }
        else
        {
            throw new HttpRequestException($"Http method {method.Method} not supported");
        }

        var stringResponse = await response.GetStringAsync();
        if (stringResponse is null or "" or "null" or "{}")
            return new TResponse();

        try
        {
            return JsonSerializer.Deserialize<TResponse>(stringResponse, CommonStatics.DefaultJsonOptions)!;
        }
        catch (Exception e)
        {
            throw new HttpRequestException($"Invalid json response {stringResponse}", e);
        }
    }
}